package main

import (
	"bufio"
	"fmt"
	"github.com/lucasepe/codename"
	"go-tcp-server/frame"
	"go-tcp-server/packet"
	"net"
	"sync"
	"time"
)

func main() {

	var wg sync.WaitGroup

	var num int = 20000

	wg.Add(num)

	for i := 0; i < num; i++ {
		go func(i int) {
			defer wg.Done()
			startClient(i)
		}(i + 1)
	}
	wg.Wait()
}

func startClient(i int) {
	quit := make(chan struct{})
	done := make(chan struct{})

	conn, err := net.Dial("tcp", ":9998")
	if err != nil {
		fmt.Println("dial error:", err)
		return
	}
	defer conn.Close()
	fmt.Printf("[client %d]: dial ok \n", i)

	// 使用带缓存的网络 I/O解决 read，write的系统瓶颈
	// 读缓存变量（rbuf）
	rbuf := bufio.NewReader(conn)
	// 写缓存变量（wbuf）
	wbuf := bufio.NewWriter(conn)

	// 生成payload 这个包会生成一些对人类可读的随机字符
	rng, err := codename.DefaultRNG()

	if err != nil {
		panic(err)
	}

	frameCodec := frame.NewFrameCodec()

	var counter int

	// 处理 submitRequestAck 类的请求
	go func() {
		for {
			select {
			case <-quit:
				done <- struct{}{}
				return
			default:
			}
			// 使用 SetReadDeadline 方法设置了读超时
			conn.SetReadDeadline(time.Now().Add(time.Second * 5))
			// 替换掉传给 frameCodec.Decode的 conn
			// ackFramePayLoad, err := frameCodec.Decode(conn)
			ackFramePayLoad, err := frameCodec.Decode(rbuf)
			if err != nil {
				if e, ok := err.(net.Error); ok {
					if e.Timeout() {
						continue
					}
				}
				fmt.Printf("startClient frameCodec.Decode error %s \n", err.Error())
				panic(err)
			}

			p, err := packet.Decode(ackFramePayLoad)
			ack, ok := p.(*packet.SubmitRequestAck)
			if !ok {
				panic("ack is not SubmitRequestAck")
			}
			fmt.Printf("[client %d]: the result of submit ack[%s] is %d\n", i, ack.ID, ack.Result)
		}
	}()

	// 处理 submitRequest 类的请求
	for {
		counter++
		id := fmt.Sprintf("%08d", counter)
		payload := codename.Generate(rng, 4)

		request := &packet.SubmitRequest{
			ID:      id,
			Payload: []byte(payload),
		}

		framePayload, err := packet.Encode(request)

		if err != nil {
			panic(err)
		}
		fmt.Printf("[client %d]: send submit id = %s, payload=%s, frame length = %d\n", i, request.ID, request.Payload, len(framePayload)+4)

		// 替换掉传给 frameCodec.Encode的 conn
		// err = frameCodec.Encode(conn, framePayload)
		err = frameCodec.Encode(wbuf, framePayload)
		if err != nil {
			panic(err)
		}

		time.Sleep(time.Second * 1)

		if counter >= 10 {
			quit <- struct{}{}
			<-done
			fmt.Printf("[client %d]: exit ok", i)
			return
		}
	}

}
